
            <!DOCTYPE html>
            <html lang="en">
            <head>
                <meta charset="UTF-8">
                <title>5分钟搞懂如何使用探针检查Kubernetes健康</title>
            </head>
            <body>
            <a href="https://andyoung.blog.csdn.net">原作者博客</a>
            <div id="content_views" class="markdown_views prism-atom-one-light">
                    <svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
                        <path stroke-linecap="round" d="M5,0 0,2.5 5,5z" id="raphael-marker-block" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></path>
                    </svg>
                    <p>Kubernetes是一种开源容器编排平台，大大简化了应用程序的创建和管理。</p> 
<p>Kubernetes之类的分布式系统可能很难管理，原因是涉及许多活动组件，所有这些组件必须正常工作，整个系统才能顺畅运行。即使某个小组件坏掉，也需要检测和修复它。</p> 
<p>这些操作还需要自动化。Kubernetes让我们可以借助就绪探针和存活探针做到这一点。本文详细讨论了这些探针，在此之前先讨论一下健康检查。</p> 
<h3><a id="_6"></a>什么是健康检查？</h3> 
<p>健康检查是一种让系统知道应用程序实例是否正常运行的简单方法。如果你的应用程序实例未正常运行，其他服务不会访问它或向它发送请求。相反，会将请求发送到另一个准备就绪的实例，或者你应该重试发送请求。</p> 
<p>系统应该能够使你的应用程序处于健康状态。默认情况下，pod内的所有容器都已启动后，Kubernetes会开始向该pod发送流量。容器崩溃时，Kubernetes会重启容器。这个默认行为应该足以开始上手。由于Kubernetes有助于创建自定义健康检查，提高部署稳健性就变得比较简单，但我们先讨论一下pod生命周期。</p> 
<h3><a id="pod_12"></a>pod生命周期</h3> 
<p>Kubernetes pod遵循已定义的生命周期。这些是不同的阶段：</p> 
<p>• pod首次创建后，从pending（挂起）阶段开始。调度器试图搞清楚把pod放置在哪里。如果调度器找不到放置pod的节点，它将保持挂起状态。（要检查pod为何处于挂起状态，运行kubectl describe pod 命令）。</p> 
<p>• 一旦pod被调度，它进入容器creating（创建）阶段，在此阶段拉取应用程序所需的镜像，随后容器启动。</p> 
<p>• 一旦容器在pod中，它进入running（运行）阶段，在此阶段它继续运行，直至程序成功完成或终止。</p> 
<p>要检查pod的状态，请运行kubectl get pod命令，检查STATUS列。如你所见，在这种情况下，所有pod都处于运行状态。此外，READY列表明pod已准备好接受用户流量。</p> 
<pre><code># kubectl get pod
 
NAME READY STATUS RESTARTS AGE
 
my-nginx-6b74b79f57-fldq6 1/1 Running 0 20s
 
my-nginx-6b74b79f57-n67wp 1/1 Running 0 20s
 
my-nginx-6b74b79f57-r6pcq 1/1 Running 0 20s
</code></pre> 
<h3><a id="Kubernetes_36"></a>Kubernetes中不同类型的探针</h3> 
<p>Kubernetes提供了以下类型的健康检查：</p> 
<p>• 就绪探针：该探针将告诉你应用程序何时准备为流量提供服务。在允许服务向pod发送流量之前，Kubernetes将确保就绪探针通过。如果就绪探针未通过，Kubernetes不会向pod发送流量，直至探针通过。</p> 
<p>• 存活探针：存活探针会让Kubernetes可以知道你的应用程序是否健康。如果应用程序健康，Kubernetes不会干扰pod的运行，但如果不健康，Kubernetes就会销毁pod，并启动新的pod来替换它。</p> 
<p>为了进一步理解这点，不妨以实际场景为例。你的应用程序需要一些时间来预热，或从GitHub等某个外部源下载应用程序内容。除非完全准备好，否则你的应用程序不会接受流量。默认情况下，一旦容器内的进程启动，Kubernetes就会开始发送流量。使用就绪探针，Kubernetes会等到应用程序完全启动后，才允许服务将流量发送到新副本。</p> 
<p>不妨看另一种场景：你的应用程序因代码错误而崩溃（可能是极端情况），并且无限期挂起，停止为请求提供服务。由于你的进程默认继续运行，Kubernetes会将流量发送到坏掉的pod。使用存活探针，Kubernetes将检测到应用程序不再为请求提供服务，默认情况下重启出故障的pod。</p> 
<p>现在看看如何定义探针。探针有三种类型：</p> 
<p>• HTTP</p> 
<p>• TCP</p> 
<p>• 命令</p> 
<p>**注意：**你可以选择从定义就绪探针或存活探针开始，因为两者的实现都需要类似的模板。比如说，如果我们先定义存活探针，可以使用它来定义就绪探针，反之亦然。</p> 
<p>• HTTP探针（httpGet）：这是最常见的探针类型。即使你的应用程序不是HTTP服务器，通常也可以在应用程序内创建轻量级 HTTP服务器以响应存活探针。Kubernetes将在特定端口（本例中端口8080）乒测ping路径（比如/healthz）。如果它收到200或300范围内的HTTP响应，将被标记为健康。（想进一步了解HTTP响应代码，请参阅该链接https://developer.mozilla.org/en-US/docs/Web/HTTP/Status）。否则，它会被标记为不健康。以下是定义HTTP存活探针的方法：</p> 
<pre><code>livenessProbe:
httpGet:
path: /healthz
port: 8080
</code></pre> 
<p>HTTP就绪探针的定义与HTTP存活探针类似，你只需要把liveness换成readiness。</p> 
<pre><code>readinessProbe:
httpGet:
path: /healthz
port: 8080
</code></pre> 
<p>• TCP探针（tcpSocket）：使用TCP探针，Kubernetes会尝试在指定端口（比如下例中的8080端口）建立TCP连接。如果可以建立连接，则认为容器是健康的。如果不能，视为失败。在HTTP或命令探针无法正常工作的情况下，这些探针会很方便。比如说，FTP服务将能够使用这种类型的探针。</p> 
<pre><code>readinessProbe:
tcpSocket:
port: 8080
</code></pre> 
<p>• 命令探针（exec命令）：在命令探针情况下，Kubernetes将在你的容器内运行命令。如果命令返回退出代码0，容器将被标记为健康。否则，将被标记为不健康。当你不能或不想运行HTTP服务器时，这种类型的探针很有用，但你可以运行命令来检查应用程序是否健康。在下面示例中，我们检查文件/tmp/healthy是否存在；如果命令返回退出代码0，容器将被标记为健康；否则，它将被标记为不健康。</p> 
<pre><code>livenessProbe:
exec:
command:
- cat
- /tmp/healthy
</code></pre> 
<p>可根据需要运行的频率、成功和失败阈值以及等待响应的时间，以多种方式配置探针。</p> 
<p>• initialDelaySeconds（默认值0）：如果你知道应用程序需要n秒（比如30秒）来预热，可以使用initialDelaySeconds来添加延迟（以秒为单位），直至执行第一次检查。</p> 
<p>• periodSeconds（默认值10）：如果你想要指定执行检查的频率，可以使用periodSeconds来定义。</p> 
<p>• timeoutSeconds（默认值1）：这定义了探针操作超时之前的最大秒数。</p> 
<p>• successThreshold（默认值1）：这是在失败后探针直至被认为成功的尝试次数。</p> 
<p>• failureThreshold（默认值 3）：万一探针失败，Kubernetes会尝试多次，然后将探针标记为失败。</p> 
<p>**注意：**默认情况下，如果应用程序在尝试3次后仍未准备好，探针将停止。如果是存活探针，它将重启容器。如果是就绪探针，它会将pod标记为不健康。</p> 
<p>有关探针配置的更多信息，请参阅该链接：https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/#configure-probes。</p> 
<p>不妨结合到目前为止已讨论过的所有内容。这里要注意的关键是readinessProbe与httpGet的使用。第一次检查将在10秒后执行，然后每5秒重复一次。</p> 
<pre><code>apiVersion: v1
 
kind: Pod
 
metadata:
 
labels:
 
run: nginx
 
name: nginx
 
spec:
 
containers:
 
- image: nginx
 
name: nginx
 
readinessProbe:
 
httpGet:
 
path: /
 
port: 80
 
initialDelaySeconds: 10
 
periodSeconds: 5
</code></pre> 
<p>• 要创建pod，请使用kubectl create命令，并使用-f标志指定YAML清单文件。你可以为该文件取任何名称，但后缀名应该是.yaml。</p> 
<pre><code>kubectl create -f readinessprobe.yaml

pod/nginx created
</code></pre> 
<p>• 如果你现在检查pod的状态，它应该在STATUS列下显示状态为Running。但如果你检查READY列，它仍然会显示0/1，这意味着它没有准备好接受新的连接。</p> 
<pre><code>kubectl get pod
 
NAME READY STATUS RESTARTS AGE
 
nginx 0/1 Running 0 16s
</code></pre> 
<p>• 由于我们将初始延迟设置为1秒，几秒钟后验证状态。现在，pod应该在运行。</p> 
<pre><code>kubectl get pod
 
NAME READY STATUS RESTARTS AGE
 
nginx 1/1 Running 0 28s

</code></pre> 
<p>• 要检查定义就绪探针时使用的所有参数（比如initialDelaySeconds、periodSeconds等）的详细状态，运行kubectl describe命令。</p> 
<pre><code>kubectl describe pod nginx |grep -i readiness
 
Readiness: http-get http://:80/ delay=10s timeout=1s period=5s #success=1 #failure=3

</code></pre> 
<p>不妨通过一个例子进一步加深对存活探针和就绪探针概念的了解。先从活性探针开始。在下面例子中，我们在执行命令：</p> 
<p>touch healthy; sleep 20; rm -rf healthy; sleep 600’。</p> 
<p>借助该命令，我们使用touch 命令创建了文件名“healthy”。该文件前20秒将存在于容器中，然后使用rm -rf命令将其删除。最后，容器将休眠600秒。</p> 
<p>随后我们定义了存活探针。它先使用cat health命令检查该文件是否存在。它以5秒的初始延迟完成此操作。我们进一步定义了参数periodSeconds，它每5秒就执行存活探针。一旦我们删除该文件，20秒后，探针将处于失败状态。</p> 
<pre><code>apiVersion: v1
 
kind: Pod
 
metadata:
 
labels:
 
name: liveness-probe-exec
 
spec:
 
containers:
 
- name: liveness-probe
 
image: busybox
 
args:
 
- /bin/sh
 
- -c
 
- touch healthy; sleep 20; rm -rf healthy; sleep 600
 
livenessProbe:
 
exec:
 
command:
 
- cat
 
- healthy
 
initialDelaySeconds: 5
 
periodSeconds: 5

</code></pre> 
<p>• 要创建pod，将上述代码存储在以.yaml结尾的文件中（比如liveness-probe.yaml），然后使用-f 执行kubectl create命令，这将创建pod。</p> 
<pre><code># kubectl create -f liveness-probe.yaml
 
pod/liveness-probe-exec created

</code></pre> 
<p>• 运行kubectl get events命令，你会看到存活探针已失败，容器已被杀死并重启。</p> 
<pre><code>54s Normal Scheduled pod/liveness-probe-exec Successfully assigned default/liveness-probe-exec to controlplane
 
53s Normal Pulling pod/liveness-probe-exec Pulling image "busybox"
 
52s Normal Pulled pod/liveness-probe-exec Successfully pulled image "busybox" in 384.330188ms
 
52s Normal Created pod/liveness-probe-exec Created container liveness-probe
 
52s Normal Started pod/liveness-probe-exec Started container liveness-probe
 
18s Warning Unhealthy pod/liveness-probe-exec Liveness probe failed: cat: can't open 'healthy': No such file or directory
 
18s Normal Killing pod/liveness-probe-exec Container liveness-probe failed liveness probe, will be restarted
</code></pre> 
<p>• 你还可以使用kubectl get pods命令进行验证，正如你在重启列中看到，容器重启了一次。</p> 
<pre><code># kubectl get pods
 
NAME READY STATUS RESTARTS AGE
 
liveness-probe-exec 1/1 Running 1 24s
</code></pre> 
<p>• 现在你已了解存活探针的工作原理，不妨调整上面的例子将其定义为就绪探针，以此了解就绪探针的工作原理。在下面例子中，我们在容器内执行命令（sleep 20; touch healthy; sleep 600），它先休眠20秒，创建一个文件，最后休眠600秒。由于初始延迟设置为15秒，第一次检查以15 秒延迟来执行。</p> 
<pre><code>apiVersion: v1
 
kind: Pod
 
metadata:
 
labels:
 
name: readiness-probe-exec
 
spec:
 
containers:
 
- name: readiness-probe
 
image: busybox
 
args:
 
- /bin/sh
 
- -c
 
- sleep 20;touch healthy;sleep 600
 
readinessProbe:
 
exec:
 
command:
 
- cat
 
- healthy
 
initialDelaySeconds: 15
 
periodSeconds: 5
</code></pre> 
<p>• 要创建pod，将上述代码存储在以.yaml结尾的文件中，然后执行kubectl create命令，该命令将创建pod。</p> 
<pre><code># kubectl create -f readiness-probe.yaml
 
pod/readiness-probe-exec created
</code></pre> 
<p>• 如果你在这里执行kubectl get events，会看到探针失败，因为文件不存在。</p> 
<pre><code>63s Normal Scheduled pod/readiness-probe-exec Successfully assigned default/readiness-probe-exec to controlplane
 
62s Normal Pulling pod/readiness-probe-exec Pulling image "busybox"
 
62s Normal Pulled pod/readiness-probe-exec Successfully pulled image "busybox" in 156.57701ms
 
61s Normal Created pod/readiness-probe-exec Created container readiness-probe
 
61s Normal Started pod/readiness-probe-exec Started container readiness-probe
 
42s Warning Unhealthy pod/readiness-probe-exec Readiness probe failed: cat: can't open 'healthy': No such file or directory
 
If you check the status of the container initially, it is not in a ready state.
 
# kubectl get pods
 
NAME READY STATUS RESTARTS AGE
 
readiness-probe-exec 0/1 Running 0 5s
</code></pre> 
<p>• 但是如果你在20秒后检查它，它应该处于运行状态。</p> 
<pre><code># kubectl get pods
 
NAME READY STATUS RESTARTS AGE
 
readiness-probe-exec 1/1 Running 0 27s
</code></pre> 
<h3><a id="_358"></a>结论</h3> 
<p>任何分布式系统都需要检查健康，Kubernetes也不例外。使用健康检查为你的Kubernetes服务提供稳固的基础、更高的可靠性和更长的正常运行时间。</p>
                </div>
            </body>
            </html>
            